#include "Generator.h"
#include "GeneratorEnvironment.h"
#include "Trace.h"

namespace tsc
{
namespace common
{

/*******************************************************************************
 *
 * Constructor
 *
 ******************************************************************************/
Generator::Generator(
		GeneratorEnvironment& ge,
		StateBase* pInitialState) :
	_generatorId(-1),
	_currentState(pInitialState),
	_isRunning(false),
	_ge(ge),
	_isRemoved(false)
{

} // Generator::Generator

/*******************************************************************************
 *
 * Destructor
 *
 ******************************************************************************/
Generator::~Generator()
{
	std::deque<EventData*>::iterator it = _eventQueue.begin();
	while(it != _eventQueue.end())
	{
		delete *it;
		it = _eventQueue.erase(it);
	}
} // Generator::~Generator

int Generator::getGeneratorId() const
{
	return _generatorId;
}

void Generator::setGeneratorId(int generatorId)
{
	_generatorId = generatorId;
}

StateBase* Generator::getCurrentState() const
{
	return _currentState;
}

void Generator::changeState(StateBase* newState)
{
	if(newState != 0 && newState != _currentState)
	{
	    STATE_CHANGE("Changing state: %s -> %s",
                         _currentState->getName(),
                         newState->getName());
		_currentState = newState;
	}
}

void Generator::injectEvent(EventData*& event)
{
	if(!event)
	{
		TRACE_ERROR("Trying to inject NULL event");
    RETURN;
	}

	if(!_isRunning)
	{
		TRACE(7, "Generator is NOT running, handling event:0x%x", event->sigNo());
		_isRunning = true;
		_currentState->handleEvent(this, event);
		_isRunning = false;
	}
	else
	{
		TRACE(7, "Generator is running, putting event:0x%x to queue", event->sigNo());

		_eventQueue.push_back(event);
		// set pointer to 0 to indicate that event was handled
		event = 0;
		RETURN;
	}

	eventLoop();
	RETURN;
}

void
Generator::eventLoop()
{
	TRACE(7, "eventLoop, genId=%u, isRunning=%u, eventQueue size=%u",
				 getGeneratorId(), _isRunning, _eventQueue.size());

	_isRunning = true;

	while(!_eventQueue.empty())
	{
		EventData* event = _eventQueue.front();
		TRACE(7, "eventLoop, handling event:0x%x in state:%s", event->sigNo(), getCurrentState()->getName());
		_eventQueue.pop_front();
		_currentState->handleEvent(this, event);
		if(event)
		{
			TRACE_ERROR("Event:0x%x not handled in state:%s",
					event->sigNo(), getCurrentState()->getName());
			EventData::deleteEvent(event);
		}

		TRACE(7, "Handled event, queue size=%u", _eventQueue.size());
	}
	_isRunning = false;
}

void
Generator::removeGenerator()
{
	if(!_isRemoved)
	{
		_ge.addToRemoveList(this);
		_isRemoved = true;
	}
}

} // namespace common
} // namespace tsc
